#include "connectionPool.hpp"
#include <iostream>
using namespace std;

// 连接池配置
static int initSize = 10;  // 初始的链接池链接量
static int maxSize = 1024; // 最大的链接池链接量
// 最大空闲时间默认单位是秒
static int maxIdleTime = 10; // 连接池最大空闲时间
// 连接超时时间单位是毫秒
static int connectionTimeOut = 1000; // 最大连接空闲时间-是否进行释放

/**
 * @brief 获取连接池实例
 *
 * @return ConnectionPool*
 */
ConnectionPool *ConnectionPool::getConnectionPool()
{
    static ConnectionPool pool;
    return &pool;
}
/**
 * @brief 消费者从连接池中获取连接
 *
 * @return shared_ptr<MySQL>
 */
shared_ptr<MySQL> ConnectionPool::getMySQL()
{
    unique_lock<mutex> lock(_queueMutex);
    // 没有连接时
    while (_connectionQue.empty())
    {
        // 等待定长时间
        if (cv_status::timeout == _cv.wait_for(lock, chrono::milliseconds(connectionTimeOut)))
        {
            LOG_INFO << "获取连接超时...连接失败...";
            return nullptr;
        }
        // 唤醒后继续判断是否有空连接可获取
    }
    // 获取连接
    // 利用智能指针,析构时做连接的归还-需自定义删除器
    shared_ptr<MySQL> sp(_connectionQue.front(),
                         [&](MySQL *pcon)
                         {
                             unique_lock<mutex> lock(_queueMutex); // 此时处于服务器应用线程中
                             pcon->refreshAliveTime();
                             _connectionQue.push(pcon);
                         });
    _connectionQue.pop();
    _connectionCnt--;
    _cv.notify_all(); // 通知消费线程

    return sp;
}
/**
 * @brief 单例模式-静态方法中构造静态对象时调用
 *
 */
ConnectionPool::ConnectionPool()
{
    // 创建初始数量的连接
    for (int i = 0; i < initSize; i++)
    {
        MySQL *con = new MySQL();
        con->connect();
        con->refreshAliveTime();
        _connectionQue.push(con);
        _connectionCnt++;
    }
    // 创建独立线程负责连接生产和空闲连接的扫描
    // 传入类成员函数需要进行对象绑定,调用
    thread produce(bind(&ConnectionPool::produceConnectionTask, this));
    produce.detach();

    thread scanner(bind(&ConnectionPool::scannerConnectionTask, this));
    scanner.detach();
}
/**
 * @brief 独立线程-负责生产连接
 *
 */
void ConnectionPool::produceConnectionTask()
{
    while (true)
    {
        unique_lock<mutex> lock(_queueMutex);
        // 没有连接才生产
        while (!_connectionQue.empty())
        {
            _cv.wait(lock);
        }
        if (_connectionCnt < maxSize)
        {
            MySQL *con = new MySQL();
            con->connect();
            con->refreshAliveTime();
            _connectionQue.push(con);
            _connectionCnt++;
        }
        _cv.notify_all();
    }
}
/**
 * @brief 独立线程-定时扫描队列中的空闲连接,进行释放
 *
 */
void ConnectionPool::scannerConnectionTask()
{
    while (true)
    {
        this_thread::sleep_for(chrono::seconds(maxIdleTime)); // 定时
        unique_lock<mutex> lock(_queueMutex);
        while (_connectionCnt > initSize)
        {
            MySQL *con = _connectionQue.front();
            if (con->getAliveTime() >= (maxIdleTime * 1000))
            {
                _connectionQue.pop();
                _connectionCnt--;
                delete con; // 真正释放
            }
            else
                break;
        }
    }
}